/*

   Derby - Class org.apache.derby.impl.sql.compile.ResultColumn

   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to you under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

 */

package org.apache.dearbaby.impl.sql.compile;

import java.util.List;

import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.iapi.reference.StandardException;
import org.apache.derby.iapi.services.compiler.MethodBuilder;
import org.apache.derby.iapi.services.context.ContextManager;
import org.apache.derby.iapi.services.io.StoredFormatIds;
import org.apache.derby.iapi.sql.ResultColumnDescriptor;
import org.apache.derby.iapi.sql.compile.Visitor;
import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
import org.apache.derby.iapi.sql.dictionary.TableDescriptor; 
import org.apache.derby.iapi.types.DataTypeDescriptor;
import org.apache.derby.iapi.types.DataValueDescriptor;
import org.apache.derby.iapi.types.DataValueFactory;
import org.apache.derby.iapi.types.StringDataValue;
import org.apache.derby.iapi.types.TypeId;
import org.apache.derby.iapi.util.StringUtil;
import org.apache.derby.shared.common.sanity.SanityManager;

/**
 * A ResultColumn represents a result column in a SELECT, INSERT, or UPDATE
 * statement. In a SELECT statement, the result column just represents an
 * expression in a row being returned to the client. For INSERT and UPDATE
 * statements, the result column represents an column in a stored table. So, a
 * ResultColumn has to be bound differently depending on the type of statement
 * it appears in.
 * <P>
 * The type of the ResultColumn can differ from its underlying expression, for
 * example in certain joins the ResultColumn can be nullable even if its
 * underlying column is not. In an INSERT or UPDATE the ResultColumn will
 * represent the type of the column in the table, the type of the underlying
 * expression will be the type of the source of the value to be insert or
 * updated. The method columnTypeAndLengthMatch() can be used to detect when
 * normalization is required between the expression and the type of
 * ResultColumn. This class does not implement any type normalization
 * (conversion), this is typically handled by a NormalizeResultSetNode.
 *
 */

public class ResultColumn extends ValueNode implements ResultColumnDescriptor,
		Comparable<ResultColumn> {
	/*
	 * _underlyingName and _derivedColumnName should point to the same string,
	 * unless there is a derived column list, in which case _underlyingName will
	 * point to the underlying name and _derivedColumnName will point to the
	 * name from the derived column list.
	 */
	public String _underlyingName; // name from the actual data source
	public String _derivedColumnName;
	public String _unqualifiedTableName;
	public String _unqualifiedSourceTableName;
	// Used by metadata api ResultSetMetaData.getSchemaName to get a column's
	// table's schema.
	private String _sourceSchemaName;
	public ValueNode _expression;
	private ColumnDescriptor _columnDescriptor;
	private boolean _isGenerated;
	private boolean _isGeneratedForUnmatchedColumnInInsert;
	private boolean _isGroupingColumn;
	private boolean _isReferenced;
	private boolean _isRedundant;
	private boolean _isNameGenerated;
	private boolean _updated;
	private boolean _updatableByCursor;
	private boolean defaultColumn;
	private boolean wasDefault;
	// Following 2 fields have been added for DERBY-4631.
	// rightOuterJoinUsingClause will be set to true for following 2 cases
	// 1)if this column represents the join column which is part of the
	// SELECT list of a RIGHT OUTER JOIN with USING/NATURAL. eg
	// select c from t1 right join t2 using (c)
	// This case is talking about column c as in "select c"
	// 2)if this column represents the join column from the right table
	// for predicates generated for the USING/NATURAL of RIGHT OUTER JOIN
	// eg
	// select c from t1 right join t2 using (c)
	// For "using(c)", a join predicate will be created as follows
	// t1.c=t2.c
	// This case is talking about column t2.c of the join predicate.
	private boolean rightOuterJoinUsingClause;
	// Following will be non-null for the case 1) above. It will show the
	// association of this result column to the join resultset created
	// for the RIGHT OUTER JOIN with USING/NATURAL. This information along
	// with rightOuterJoinUsingClause will be used during the code generation
	// time.
	private JoinNode joinResultSet = null;

	// tells us if this ResultColumn is a placeholder for a generated
	// autoincrement value for an insert statement.
	private boolean _autoincrementGenerated;

	// tells us if this ResultColumn represents an autoincrement column in a
	// base table.
	private boolean _autoincrement;

	/* ResultSetNumber for the ResultSet (at generate() time) that we belong to */
	private int resultSetNumber = -1;
	private ColumnReference _reference; // used to verify quals at bind time, if
										// given.

	/*
	 * virtualColumnId is the ResultColumn's position (1-based) within the
	 * ResultSet
	 */
	private int virtualColumnId;

	ResultColumn(ContextManager cm) {
		super(cm);
	}

	/**
	 * @param underlyingName
	 *            The name of the column, if any.
	 * @param expression
	 *            The expression this result column represents
	 * @param cm
	 *            context manager
	 */
	ResultColumn(String underlyingName, ValueNode expression, ContextManager cm)
			throws StandardException {
		super(cm);
		setTypeExpressionAndDefault(expression);
		_underlyingName = underlyingName;
		_derivedColumnName = _underlyingName;
	}

	/**
	 * @param cr
	 *            A column reference node
	 * @param expression
	 *            The expression this result column represents
	 * @param cm
	 *            context manager
	 * @throws StandardException
	 */
	ResultColumn(ColumnReference cr, ValueNode expression, ContextManager cm)
			throws StandardException {
		super(cm);
		setTypeExpressionAndDefault(expression);
		_underlyingName = cr.getColumnName();
		_derivedColumnName = cr.getColumnName();

		// When we bind, we'll want to make sure the reference has the right
		// table name.
		_reference = cr;
	}

	/**
	 * @param cd
	 *            The column descriptor
	 * @param expression
	 *            The expression this result column represents
	 * @param cm
	 *            context manager
	 * @throws StandardException
	 */
	ResultColumn(ColumnDescriptor cd, ValueNode expression, ContextManager cm)
			throws StandardException {
		super(cm);
		setTypeExpressionAndDefault(expression);
		_underlyingName = cd.getColumnName();
		_derivedColumnName = _underlyingName;
		setType(cd.getType());
		_columnDescriptor = cd;
		_autoincrement = cd.isAutoincrement();
	}

	/**
	 * @param dtd
	 *            The type of the column
	 * @param expression
	 *            The expression this result column represents
	 * @param cm
	 *            context manager
	 * @throws StandardException
	 */
	ResultColumn(DataTypeDescriptor dtd, ValueNode expression, ContextManager cm)
			throws StandardException {
		super(cm);
		setTypeExpressionAndDefault(expression);
		setType(dtd);

		if (_expression instanceof ColumnReference) {
			_reference = (ColumnReference) expression;
		}
	}

	private void setTypeExpressionAndDefault(ValueNode expression) {
		setExpression(expression);

		if (expression != null && expression instanceof DefaultNode) {
			// This result column represents a <default> keyword in an insert or
			// update statement
			defaultColumn = true;
		}
	}

	/**
	 * Returns TRUE if the ResultColumn is join column for a RIGHT OUTER JOIN
	 * with USING/NATURAL. More comments at the top of this class where
	 * rightOuterJoinUsingClause is defined.
	 */
	boolean isRightOuterJoinUsingClause() {
		return rightOuterJoinUsingClause;
	}

	/**
	 * Will be set to TRUE if this ResultColumn is join column for a RIGHT OUTER
	 * JOIN with USING/NATURAL. More comments at the top of this class where
	 * rightOuterJoinUsingClause is defined. 2 eg cases 1)select c from t1 right
	 * join t2 using (c) This case is talking about column c as in "select c"
	 * 2)select c from t1 right join t2 using (c) For "using(c)", a join
	 * predicate will be created as follows t1.c=t2.c This case is talking about
	 * column t2.c of the join predicate.
	 * 
	 * This method gets called for Case 1) during the bind phase of
	 * ResultColumn(ResultColumn.bindExpression).
	 * 
	 * This method gets called for Case 2) during the bind phase of JoinNode
	 * while we are going through the list of join columns for a NATURAL JOIN or
	 * user supplied list of join columns for USING
	 * clause(JoinNode.getMatchingColumn).
	 * 
	 * @param value
	 *            True/False
	 */
	void setRightOuterJoinUsingClause(boolean value) {
		rightOuterJoinUsingClause = value;
	}

	/**
	 * Returns a non-null value if the ResultColumn represents the join column
	 * which is part of the SELECT list of a RIGHT OUTER JOIN with
	 * USING/NATURAL. eg select c from t1 right join t2 using (c) The join
	 * column we are talking about is column c as in "select c" The return value
	 * of following method will show the association of this result column to
	 * the join resultset created for the RIGHT OUTER JOIN with USING/NATURAL.
	 * This information along with rightOuterJoinUsingClause will be used during
	 * the code generation time.
	 */
	JoinNode getJoinResultSet() {
		return joinResultSet;
	}

	/**
	 * This method gets called during the bind phase of a ResultColumn if it is
	 * determined that the ResultColumn represents the join column which is part
	 * of the SELECT list of a RIGHT OUTER JOIN with USING/NATURAL. eg select c
	 * from t1 right join t2 using (c) This case is talking about column c as in
	 * "select c"
	 * 
	 * @param resultSet
	 *            - The ResultColumn belongs to this JoinNode
	 */
	void setJoinResultset(JoinNode resultSet) {
		joinResultSet = resultSet;
	}

	/**
	 * Returns TRUE if the ResultColumn is standing in for a DEFAULT keyword in
	 * an insert/update statement.
	 */
	boolean isDefaultColumn() {
		return defaultColumn;
	}

	void setDefaultColumn(boolean value) {
		defaultColumn = value;
	}

	/**
	 * Returns TRUE if the ResultColumn used to stand in for a DEFAULT keyword
	 * in an insert/update statement.
	 */
	boolean wasDefaultColumn() {
		return wasDefault;
	}

	void setWasDefaultColumn(boolean value) {
		wasDefault = value;
	}

	/**
	 * Return TRUE if this result column matches the provided column name.
	 *
	 * This function is used by ORDER BY column resolution. For the ORDER BY
	 * clause, Derby will prefer to match on the column's alias
	 * (_derivedColumnName), but will also successfully match on the underlying
	 * column name. Thus the following statements are treated equally: select
	 * name from person order by name; select name as person_name from person
	 * order by name; select name as person_name from person order by
	 * person_name; See DERBY-2351 for more discussion.
	 */
	boolean columnNameMatches(String columnName) {
		return columnName.equals(_derivedColumnName)
				|| columnName.equals(_underlyingName)
				|| columnName.equals(getSourceColumnName());
	}

	public Object getVal() {
		return  getColVal(getTableName(),getSourceColumnName());
	}
	/**
	 * Get non-null column name. This method is called during the bind phase to
	 * see if we are dealing with ResultColumn in the SELECT list that belongs
	 * to a RIGHT OUTER JOIN(NATURAL OR USING)'s join column.
	 * 
	 * For a query like following, we want to use column name x and not the
	 * alias x1 when looking in the JoinNode for join column SELECT x x1 FROM
	 * derby4631_t2 NATURAL RIGHT OUTER JOIN derby4631_t1; For a query like
	 * following, getSourceColumnName() will return null because we are dealing
	 * with a function for the column. For this case, "name" will return the
	 * alias name cx SELECT coalesce(derby4631_t2.x, derby4631_t1.x) cx FROM
	 * derby4631_t2 NATURAL RIGHT OUTER JOIN derby4631_t1; For a query like
	 * following, getSourceColumnName() and name will return null and hence need
	 * to use the generated name SELECT ''dummy="'|| TRIM(CHAR(x))|| '"' FROM
	 * (derby4631_t2 NATURAL RIGHT OUTER JOIN derby4631_t1);
	 */
	String getUnderlyingOrAliasName() {
		if (getSourceColumnName() != null) {
			return getSourceColumnName();
		} else if (_underlyingName != null) {
			return _underlyingName;
		} else {
			return _derivedColumnName;
		}
	}

	/**
	 * Returns the underlying source column name, if this ResultColumn is a
	 * simple direct reference to a table column, or NULL otherwise.
	 */
	public String getSourceColumnName() {
		if (_expression instanceof ColumnReference)
			return ((ColumnReference) _expression).getColumnName();
		return null;
	}

	/**
	 * The following methods implement the ResultColumnDescriptor interface. See
	 * the Language Module Interface for details.
	 */

	public String getName() {
		return _derivedColumnName;
	}

	@Override
	String getSchemaName() throws StandardException {
		if ((_columnDescriptor != null)
				&& (_columnDescriptor.getTableDescriptor() != null))
			return _columnDescriptor.getTableDescriptor().getSchemaName();
		else {
			if (_expression != null)
				// REMIND: could look in reference, if set.
				return _expression.getSchemaName();
			else
				return null;
		}
	}

	@Override
	String getTableName() {
		if (_unqualifiedTableName != null) {
			return _unqualifiedTableName;
		}
		if ((_columnDescriptor != null)
				&& (_columnDescriptor.getTableDescriptor() != null)) {
			return _columnDescriptor.getTableDescriptor().getName();
		} else {
			return _expression.getTableName();
		}
	}

	/**
	 * @see ResultColumnDescriptor#getSourceTableName
	 */
	public String getSourceTableName() {
		return _unqualifiedSourceTableName;
	}

	/**
	 * @see ResultColumnDescriptor#getSourceSchemaName
	 */
	public String getSourceSchemaName() {
		return _sourceSchemaName;
	}

	/**
	 * Clear the table name for the underlying ColumnReference. See
	 * UpdateNode.scrubResultColumns() for full explaination.
	 */
	void clearTableName() {
		if (_expression instanceof ColumnReference) {
			((ColumnReference) _expression)
					.setQualifiedTableName((TableName) null);
		}
	}

	public DataTypeDescriptor getType() {
		return getTypeServices();
	}

	public int getColumnPosition() {
		if (_columnDescriptor != null)
			return _columnDescriptor.getPosition();
		else
			return virtualColumnId;

	}

	/**
	 * Set the expression in this ResultColumn. This is useful in those cases
	 * where you don't know the expression in advance, like for INSERT
	 * statements with column lists, where the column list and SELECT or VALUES
	 * clause are parsed separately, and then have to be hooked up.
	 *
	 * @param expression
	 *            The expression to be set in this ResultColumn
	 */

	void setExpression(ValueNode expression) {
		_expression = expression;
	}

	/**
	 * Get the expression in this ResultColumn.
	 *
	 * @return ValueNode this.expression
	 */

	ValueNode getExpression() {
		return _expression;
	}

	/**
	 * Set the expression to a null node of the correct type.
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */
	void setExpressionToNullNode() throws StandardException {
		setExpression(getNullNode(getTypeServices()));
	}

	/**
	 * Set the name in this ResultColumn. This is useful when you don't know the
	 * name at the time you create the ResultColumn, for example, in an
	 * insert-select statement, where you want the names of the result columns
	 * to match the table being inserted into, not the table they came from.
	 *
	 * @param name
	 *            The name to set in this ResultColumn
	 */

	void setName(String name) {
		if (_underlyingName == null) {
			_underlyingName = name;
		} else {
			if (SanityManager.DEBUG)
				SanityManager.ASSERT(
						_reference == null
								|| name.equals(_reference.getColumnName()),
						"don't change name from reference name");
		}

		_derivedColumnName = name;
	}

	/**
	 * Is the name for this ResultColumn generated?
	 */
	boolean isNameGenerated() {
		return _isNameGenerated;
	}

	/**
	 * Set that this result column name is generated.
	 */
	void setNameGenerated(boolean value) {
		_isNameGenerated = value;
	}

	/**
	 * Set the resultSetNumber for this ResultColumn. This is the
	 * resultSetNumber for the ResultSet that we belong to. This is useful for
	 * generate() and necessary since we do not have a back pointer to the RSN.
	 *
	 * @param resultSetNumber
	 *            The resultSetNumber.
	 */
	void setResultSetNumber(int resultSetNumber) {
		this.resultSetNumber = resultSetNumber;
	}

	/**
	 * Get the resultSetNumber for this ResultColumn.
	 *
	 * @return int The resultSetNumber.
	 */
	public int getResultSetNumber() {
		return resultSetNumber;
	}

	/**
	 * Adjust the virtualColumnId for this ResultColumn by the specified amount
	 * 
	 * @param adjust
	 *            The adjustment for the virtualColumnId
	 */

	void adjustVirtualColumnId(int adjust) {
		virtualColumnId += adjust;
	}

	/**
	 * Set the virtualColumnId for this ResultColumn
	 * 
	 * @param id
	 *            The virtualColumnId for this ResultColumn
	 */

	void setVirtualColumnId(int id) {
		virtualColumnId = id;
	}

	/**
	 * Get the virtualColumnId for this ResultColumn
	 *
	 * @return virtualColumnId for this ResultColumn
	 */
	int getVirtualColumnId() {
		return virtualColumnId;
	}

	/**
	 * Adjust this virtualColumnId to account for the removal of a column
	 *
	 * This routine is called when bind processing finds and removes duplicate
	 * columns in the result list which were pulled up due to their presence in
	 * the ORDER BY clause, but were later found to be duplicate.
	 * 
	 * If this column is a virtual column, and if this column's virtual column
	 * id is greater than the column id which is being removed, then we must
	 * logically shift this column to the left by decrementing its virtual
	 * column id.
	 *
	 * @param removedColumnId
	 *            id of the column being removed.
	 */
	void collapseVirtualColumnIdGap(int removedColumnId) {
		if (_columnDescriptor == null && virtualColumnId > removedColumnId)
			virtualColumnId--;
	}

	/**
	 * Generate a unique (across the entire statement) column name for unnamed
	 * ResultColumns
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */
	void guaranteeColumnName() throws StandardException {
		if (_derivedColumnName == null) {
			/*
			 * Unions may also need generated names, if both sides name don't
			 * match
			 */
			_derivedColumnName = "SQLCol"
					+ getCompilerContext().getNextColumnNumber();
			_isNameGenerated = true;
		}
	}

	/**
	 * Convert this object to a String. See comments in QueryTreeNode.java for
	 * how this should be done for tree printing.
	 *
	 * @return This object as a String
	 */
	@Override
	public String toString() {
		if (SanityManager.DEBUG) {
			return "derivedColumnName: " + _derivedColumnName + "\n"
					+ "underlyingName: " + _underlyingName + "\n"
					+ "tableName: " + _unqualifiedTableName + "\n"
					+ "isDefaultColumn: " + defaultColumn + "\n"
					+ "wasDefaultColumn: " + wasDefault + "\n"
					+ "isNameGenerated: " + _isNameGenerated + "\n"
					+ "sourceTableName: " + _unqualifiedSourceTableName + "\n"
					+ "type: " + getTypeServices() + "\n"
					+ "columnDescriptor: " + _columnDescriptor + "\n"
					+ "isGenerated: " + _isGenerated + "\n"
					+ "isGeneratedForUnmatchedColumnInInsert: "
					+ _isGeneratedForUnmatchedColumnInInsert + "\n"
					+ "isGroupingColumn: " + _isGroupingColumn + "\n"
					+ "isReferenced: " + _isReferenced + "\n" + "isRedundant: "
					+ _isRedundant + "\n" + "rightOuterJoinUsingClause: "
					+ rightOuterJoinUsingClause + "\n" + "joinResultSet: "
					+ joinResultSet + "\n" + "virtualColumnId: "
					+ virtualColumnId + "\n" + "resultSetNumber: "
					+ resultSetNumber + "\n" + super.toString();
		} else {
			return "";
		}
	}

	/**
	 * Prints the sub-nodes of this object. See QueryTreeNode.java for how tree
	 * printing is supposed to work.
	 *
	 * @param depth
	 *            The depth of this node in the tree
	 */
	@Override
	void printSubNodes(int depth) {
		if (SanityManager.DEBUG) {
			super.printSubNodes(depth);
			if (_expression != null) {
				printLabel(depth, "expression: ");
				_expression.treePrint(depth + 1);
			}
			if (_reference != null) {
				printLabel(depth, "reference: ");
				_reference.treePrint(depth + 1);
			}
		}
	}

	/**
	 * Bind this expression. This means binding the sub-expressions. In this
	 * case, we figure out what the result type of this result column is when we
	 * call one of the bindResultColumn*() methods. The reason is that there are
	 * different ways of binding the result columns depending on the statement
	 * type, and this is a standard interface that does not take the statement
	 * type as a parameter.
	 *
	 * @param fromList
	 *            The FROM list for the query this expression is in, for binding
	 *            columns.
	 * @param subqueryList
	 *            The subquery list being built as we find SubqueryNodes
	 * @param aggregates
	 *            The aggregate list being built as we find AggregateNodes
	 *
	 * @return The new top of the expression tree.
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */
	@Override
	ResultColumn bindExpression(FromList fromList, SubqueryList subqueryList,
			List<AggregateNode> aggregates) throws StandardException {
		/*
		 * * Set the type of a parameter to the type of the result column.*
		 * Don't do it if this result column doesn't have a type yet.* This can
		 * happen if the parameter is part of a table constructor.
		 */
		if (_expression.requiresTypeFromContext()) {
			if (getTypeServices() != null) {
				_expression.setType(getTypeServices());
			}
		}

		// DERBY-4631
		// Following code is for a join column(which obviously will not be
		// qualified with a table name because join columns are not
		// associated with left or right table) of RIGHT OUTER JOIN
		// with USING/NATURAL join. For such columns,
		// isJoinColumnForRightOuterJoin() call will set
		// rightOuterJoinUsingClause to true and associate the
		// JoinResultSet with it. eg
		// select c from t1 right join t2 using (c)
		// Here, we are talking about column c as in "select c"
		if (_expression.getTableName() == null) {
			fromList.isJoinColumnForRightOuterJoin(this);
		}

		setExpression(_expression.bindExpression(fromList, subqueryList,
				aggregates));

		return this;
	}

	/**
	 * Bind this result column by ordinal position and set the VirtualColumnId.
	 * This is useful for INSERT statements like
	 * "insert into t values (1, 2, 3)", where the user did not specify a column
	 * list. If a columnDescriptor is not found for a given position, then the
	 * user has specified more values than the # of columns in the table and an
	 * exception is thrown.
	 *
	 * NOTE: We must set the VirtualColumnId here because INSERT does not
	 * construct the ResultColumnList in the usual way.
	 *
	 * @param tableDescriptor
	 *            The descriptor for the table being inserted into
	 * @param columnId
	 *            The ordinal position of the column in the table, starting at
	 *            1.
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */

	void bindResultColumnByPosition(TableDescriptor tableDescriptor,
			int columnId) throws StandardException {
		ColumnDescriptor colDesc;

		colDesc = tableDescriptor.getColumnDescriptor(columnId);

		if (colDesc == null) {
			String errorString;
			String schemaName;

			errorString = "";
			schemaName = tableDescriptor.getSchemaName();
			if (schemaName != null)
				errorString += schemaName + ".";
			errorString += tableDescriptor.getName();

			throw StandardException.newException(
					SQLState.LANG_TOO_MANY_RESULT_COLUMNS, errorString);
		}

		setColumnDescriptor(tableDescriptor, colDesc);
		setVirtualColumnId(columnId);
	}

	/**
	 * Bind this result column by its name and set the VirtualColumnId. This is
	 * useful for update statements, and for INSERT statements like
	 * "insert into t (a, b, c) values (1, 2, 3)" where the user specified a
	 * column list. An exception is thrown when a columnDescriptor cannot be
	 * found for a given name. (There is no column with that name.)
	 *
	 * NOTE: We must set the VirtualColumnId here because INSERT does not
	 * construct the ResultColumnList in the usual way.
	 *
	 * @param tableDescriptor
	 *            The descriptor for the table being updated or inserted into
	 * @param columnId
	 *            The ordinal position of the column in the table, starting at
	 *            1. (Used to set the VirtualColumnId.)
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */

	void bindResultColumnByName(TableDescriptor tableDescriptor, int columnId)
			throws StandardException {
		ColumnDescriptor colDesc;

		colDesc = tableDescriptor.getColumnDescriptor(_derivedColumnName);

		if (colDesc == null) {
			String errorString;
			String schemaName;

			errorString = "";
			schemaName = tableDescriptor.getSchemaName();
			if (schemaName != null)
				errorString += schemaName + ".";
			errorString += tableDescriptor.getName();

			throw StandardException.newException(
					SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE,
					_derivedColumnName, errorString);
		}

		setColumnDescriptor(tableDescriptor, colDesc);
		setVirtualColumnId(columnId);
		if (isPrivilegeCollectionRequired())
			getCompilerContext().addRequiredColumnPriv(colDesc);
	}

	/**
	 * Change an untyped null to a typed null.
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */
	void typeUntypedNullExpression(ResultColumn bindingRC)
			throws StandardException {
		TypeId typeId = bindingRC.getTypeId();
		/*
		 * This is where we catch null in a VALUES clause outside of INSERT
		 * VALUES()
		 */
		if (typeId == null) {
			throw StandardException
					.newException(SQLState.LANG_NULL_IN_VALUES_CLAUSE);
		}

		if (_expression instanceof UntypedNullConstantNode)
			// since we don't know the type of such a constant node, we just
			// use the default values for collation type and derivation.
			// eg insert into table1 values(1,null)
			// When this method is executed for the sql above, we don't know
			// the type of the null at this point.
			setExpression(getNullNode(bindingRC.getTypeServices()));
		else if ((_expression instanceof ColumnReference)
				&& _expression.getTypeServices() == null) {
			// The expression must be a reference to a null column in a values
			// table.
			_expression.setType(bindingRC.getType());
		}
	}

	/**
	 * Set the column descriptor for this result column. It also gets the data
	 * type services from the column descriptor and stores it in this result
	 * column: this is redundant, but we have to store the result type here for
	 * SELECT statements, and it is more orthogonal if the type can be found
	 * here regardless of what type of statement it is.
	 *
	 * @param tableDescriptor
	 *            The TableDescriptor for the table being updated or inserted
	 *            into. This parameter is used only for error reporting.
	 * @param columnDescriptor
	 *            The ColumnDescriptor to set in this ResultColumn.
	 *
	 * @exception StandardException
	 *                tableNameMismatch
	 */
	void setColumnDescriptor(TableDescriptor tableDescriptor,
			ColumnDescriptor columnDescriptor) throws StandardException {
		if (columnDescriptor != null) {
			setType(columnDescriptor.getType());
		}
		_columnDescriptor = columnDescriptor;

		/*
		 * If the node was created using a reference, the table name of the
		 * reference must agree with that of the tabledescriptor.
		 */
		if (_reference != null
				&& _reference.getTableName() != null
				&& (_reference.getMergeTableID() == ColumnReference.MERGE_UNKNOWN)) {
			if ((tableDescriptor != null)
					&& !tableDescriptor.getName().equals(
							_reference.getTableName())) {
				/*
				 * REMIND: need to have schema name comparison someday as
				 * well...* left out for now, lots of null checking needed...*
				 * || ! tableDescriptor.getSchemaName().equals(*
				 * reference.getQualifiedTableName().getSchemaName())) {
				 */
				String realName = tableDescriptor.getName();
				String refName = _reference.getTableName();

				throw StandardException.newException(
						SQLState.LANG_TABLE_NAME_MISMATCH, realName, refName);
			}
		}
	}

	/**
	 * Bind the result column to the expression that lives under it. All this
	 * does is copy the datatype information to this node. This is useful for
	 * SELECT statements, where the result type of each column is the type of
	 * the column's expression.
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */
	void bindResultColumnToExpression() throws StandardException {
		/*
		 * * This gets the same DataTypeServices object as* is used in the
		 * expression. It is probably not* necessary to clone the object here.
		 */
		setType(_expression.getTypeServices());

		if (_expression instanceof ColumnReference) {
			ColumnReference cr = (ColumnReference) _expression;
			_unqualifiedTableName = cr.getTableName();
			_unqualifiedSourceTableName = cr.getSourceTableName();
			_sourceSchemaName = cr.getSourceSchemaName();
		}
	}

	/**
	 * Set the column source's table name
	 * 
	 * @param t
	 *            The source table name
	 */
	void setSourceTableName(String t) {
		_unqualifiedSourceTableName = t;
	}

	/**
	 * Set the column source's schema name
	 * 
	 * @param s
	 *            The source schema name
	 */
	void setSourceSchemaName(String s) {
		_sourceSchemaName = s;
	}

	/**
	 * Preprocess an expression tree. We do a number of transformations here
	 * (including subqueries, IN lists, LIKE and BETWEEN) plus subquery
	 * flattening. NOTE: This is done before the outer ResultSetNode is
	 * preprocessed.
	 *
	 * @param numTables
	 *            Number of tables in the DML Statement
	 * @param outerFromList
	 *            FromList from outer query block
	 * @param outerSubqueryList
	 *            SubqueryList from outer query block
	 * @param outerPredicateList
	 *            PredicateList from outer query block
	 *
	 * @return The modified expression
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */
	@Override
	ResultColumn preprocess(int numTables, FromList outerFromList,
			SubqueryList outerSubqueryList, PredicateList outerPredicateList)
			throws StandardException {
		if (_expression == null)
			return this;
		setExpression(_expression.preprocess(numTables, outerFromList,
				outerSubqueryList, outerPredicateList));
		return this;
	}

	/**
	 * This verifies that the expression is storable into the result column. It
	 * checks versus the given ResultColumn.
	 * 
	 * This method should not be called until the result column and expression
	 * both have a valid type, i.e. after they are bound appropriately. Its use
	 * is for statements like insert, that need to verify if a given value can
	 * be stored into a column.
	 * 
	 * @exception StandardException
	 *                thrown if types not suitable.
	 */
	void checkStorableExpression(ResultColumn toStore) throws StandardException {
		checkStorableExpression((ValueNode) toStore);
	}

	private void checkStorableExpression(ValueNode source)
			throws StandardException {
		TypeId toStoreTypeId = source.getTypeId();

	 
	}

	/**
	 * This verifies that the expression is storable into the result column. It
	 * checks versus the expression under this ResultColumn.
	 * 
	 * This method should not be called until the result column and expression
	 * both have a valid type, i.e. after they are bound appropriately. Its use
	 * is for statements like update, that need to verify if a given value can
	 * be stored into a column.
	 * 
	 * @exception StandardException
	 *                thrown if types not suitable.
	 */
	void checkStorableExpression() throws StandardException {
		checkStorableExpression(getExpression());
	}

	/**
	 * Do code generation for a result column. This consists of doing the code
	 * generation for the underlying expression.
	 *
	 * @param ecb
	 *            The ExpressionClassBuilder for the class we're generating
	 * @param mb
	 *            The method the expression will go into
	 *
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */
	@Override
	void generateExpression(ExpressionClassBuilder ecb, MethodBuilder mb)
			throws StandardException {
		_expression.generateExpression(ecb, mb);
	}

	/**
	 * Do code generation to return a Null of the appropriate type for the
	 * result column. Requires the getCOlumnExpress value pushed onto the stack
	 *
	 * @param acb
	 *            The ActivationClassBuilder for the class we're generating
	 * @param eb
	 *            The ExpressionBlock that the generate code is to go into
	 * @param getColumnExpression
	 *            "fieldx.getColumn(y)"
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */
	/*
	 * PUSHCOMPILE void generateNulls(ExpressionClassBuilder acb, MethodBuilder
	 * mb, Expression getColumnExpress) throws StandardException {
	 * 
	 * acb.pushDataValueFactory(mb); getTypeCompiler().generateNull(mb,
	 * acb.getBaseClassName());
	 * 
	 * 
	 * mb.cast(ClassName.DataValueDescriptor);
	 * 
	 * 
	 * return eb.newCastExpression( ClassName.DataValueDescriptor,
	 * getTypeCompiler(). generateNull( eb, acb.getBaseClassName(),
	 * acb.getDataValueFactory(eb), getColumnExpress)); }
	 */

	/**
	 ** Check whether the column length and type of this result column match the
	 * expression under the columns. This is useful for INSERT and UPDATE
	 * statements. For SELECT statements this method should always return true.
	 * There is no need to call this for a DELETE statement.
	 **
	 ** @return true means the column matches its expressions, false means it
	 *         doesn't match.
	 */
	boolean columnTypeAndLengthMatch() throws StandardException {

		/*
		 * * We can never make any assumptions about* parameters. So don't even
		 * bother in this* case.
		 */
		if (getExpression().requiresTypeFromContext()) {
			return false;
		}

		// Are we inserting/updating an XML column? If so, we always
		// return false so that normalization will occur. We have to
		// do this because there are different "kinds" of XML values
		// and we need to make sure they match--but we don't know
		// the "kind" until execution time. See the "normalize"
		// method in org.apache.derby.iapi.types.XML for more.
		if (getTypeId().isXMLTypeId())
			return false;

		DataTypeDescriptor expressionType = getExpression().getTypeServices();

		if (!getTypeServices().isExactTypeAndLengthMatch(expressionType))
			return false;

		/* Is the source nullable and the target non-nullable? */
		if ((!getTypeServices().isNullable()) && expressionType.isNullable()) {
			return false;
		}

		return true;
	}

	boolean columnTypeAndLengthMatch(ResultColumn otherColumn)
			throws StandardException {
		ValueNode otherExpression = otherColumn.getExpression();

		DataTypeDescriptor resultColumnType = getTypeServices();
		DataTypeDescriptor otherResultColumnType = otherColumn
				.getTypeServices();

		if (SanityManager.DEBUG) {
			SanityManager.ASSERT(resultColumnType != null,
					"Type is null for column " + this);
			SanityManager.ASSERT(otherResultColumnType != null,
					"Type is null for column " + otherColumn);
		}

		/*
		 * * We can never make any assumptions about* parameters. So don't even
		 * bother in this* case.
		 */
		if ((otherExpression != null)
				&& (otherExpression.requiresTypeFromContext())
				|| (_expression.requiresTypeFromContext())) {
			return false;
		}

		// Are we inserting/updating an XML column? If so, we always
		// return false so that normalization will occur. We have to
		// do this because there are different "kinds" of XML values
		// and we need to make sure they match--but we don't know
		// the "kind" until execution time. See the "normalize"
		// method in org.apache.derby.iapi.types.XML for more.
		if (resultColumnType.getTypeId().isXMLTypeId())
			return false;

		/* Are they the same type? */
		if (!resultColumnType.getTypeId().equals(
				otherResultColumnType.getTypeId())) {
			/*
			 * If the source is a constant of a different type then we try to
			 * convert that constant to a constant of our type. (The initial
			 * implementation only does the conversion to string types because
			 * the most common problem is a char constant with a varchar
			 * column.) NOTE: We do not attempt any conversion here if the
			 * source is a string type and the target is not or vice versa in
			 * order to avoid problems with implicit varchar conversions.
			 * Anyway, we will check if the "converted" constant has the same
			 * type as the original constant. If not, then the conversion
			 * happened. In that case, we will reuse the ConstantNode, for
			 * simplicity, and reset the type to match the desired type.
			 */
			if (otherExpression instanceof ConstantNode) {
				ConstantNode constant = (ConstantNode) otherColumn
						.getExpression();
				DataValueDescriptor oldValue = constant.getValue();

				DataValueDescriptor newValue = convertConstant(
						resultColumnType.getTypeId(),
						resultColumnType.getMaximumWidth(), oldValue);

				if ((oldValue != newValue)
						&& (oldValue instanceof StringDataValue == newValue instanceof StringDataValue)) {
					constant.setValue(newValue);
					constant.setType(getTypeServices());
					otherColumn.bindResultColumnToExpression();
					otherResultColumnType = otherColumn.getType();
				}
				// If we are dealing with StringDataValue, then make sure we
				// have correct collation type and derivaiton set and the value
				// represented by collation is either SQLxxx or CollatorSQLxxx
				// depending on the collation type.
				if (newValue instanceof StringDataValue) {
					constant.setCollationInfo(resultColumnType);

					DataValueFactory dvf = getDataValueFactory();
					newValue = ((StringDataValue) newValue).getValue(dvf
							.getCharacterCollator(constant.getTypeServices()
									.getCollationType()));
					constant.setValue(newValue);
				}
			}
			if (!resultColumnType.getTypeId().equals(
					otherResultColumnType.getTypeId())) {
				return false;
			}
		}

		/* Are they the same precision? */
		if (resultColumnType.getPrecision() != otherResultColumnType
				.getPrecision()) {
			return false;
		}

		/* Are they the same scale? */
		if (resultColumnType.getScale() != otherResultColumnType.getScale()) {
			return false;
		}

		/* Are they the same width? */
		if (resultColumnType.getMaximumWidth() != otherResultColumnType
				.getMaximumWidth()) {
			return false;
		}

		/*
		 * Is the source nullable and the target non-nullable? The source is
		 * nullable if it is nullable or if the target is generated for an
		 * unmatched column in an insert with a column list. This additional
		 * check is needed because when we generate any additional source RCs
		 * for an insert with a column list the generated RCs for any
		 * non-specified columns get the type info from the column. Thus, for
		 * t1(non_nullable, nullable) insert into t2 (nullable) values 1;
		 * RCType.isNullable() returns false for the generated source RC for
		 * non_nullable. In this case, we want to see it as
		 */
		if ((!resultColumnType.isNullable())
				&& (otherResultColumnType.isNullable() || otherColumn
						.isGeneratedForUnmatchedColumnInInsert())) {
			return false;
		}

		return true;
	}

	/**
	 * Is this a generated column?
	 *
	 * @return Boolean - whether or not this column is a generated column.
	 */
	boolean isGenerated() {
		return (_isGenerated == true);
	}

	/**
	 * Is this columm generated for an unmatched column in an insert?
	 *
	 * @return Boolean - whether or not this columm was generated for an
	 *         unmatched column in an insert.
	 */
	boolean isGeneratedForUnmatchedColumnInInsert() {
		return (_isGeneratedForUnmatchedColumnInInsert == true);
	}

	/**
	 * Mark this a columm as a generated column
	 */
	void markGenerated() {
		_isGenerated = true;
		/* A generated column is a referenced column */
		_isReferenced = true;
	}

	/**
	 * Mark this a columm as generated for an unmatched column in an insert
	 */
	void markGeneratedForUnmatchedColumnInInsert() {
		_isGeneratedForUnmatchedColumnInInsert = true;
		/* A generated column is a referenced column */
		_isReferenced = true;
	}

	/**
	 * Is this a referenced column?
	 *
	 * @return Boolean - whether or not this column is a referenced column.
	 */
	boolean isReferenced() {
		return _isReferenced;
	}

	/**
	 * Mark this column as a referenced column.
	 */
	void setReferenced() {
		_isReferenced = true;
	}

	/**
	 * Mark this column as a referenced column if it is already marked as
	 * referenced or if any result column in its chain of virtual columns is
	 * marked as referenced.
	 */
	void pullVirtualIsReferenced() {
		if (isReferenced())
			return;

		for (ValueNode expr = _expression; expr != null
				&& (expr instanceof VirtualColumnNode);) {
			VirtualColumnNode vcn = (VirtualColumnNode) expr;
			ResultColumn src = vcn.getSourceColumn();
			if (src.isReferenced()) {
				setReferenced();
				return;
			}
			expr = src.getExpression();
		}
	} // end of pullVirtualIsReferenced

	/**
	 * Mark this column as an unreferenced column.
	 */
	void setUnreferenced() {
		_isReferenced = false;
	}

	/**
	 * Mark this RC and all RCs in the underlying RC/VCN chain as referenced.
	 */
	void markAllRCsInChainReferenced() {
		setReferenced();

		ValueNode vn = _expression;

		while (vn instanceof VirtualColumnNode) {
			VirtualColumnNode vcn = (VirtualColumnNode) vn;
			ResultColumn rc = vcn.getSourceColumn();
			rc.setReferenced();
			vn = rc.getExpression();
		}
	}

	/**
	 * Is this a redundant ResultColumn?
	 *
	 * @return Boolean - whether or not this RC is redundant.
	 */
	boolean isRedundant() {
		return _isRedundant;
	}

	/**
	 * Mark this ResultColumn as redundant.
	 */
	void setRedundant() {
		_isRedundant = true;
	}

	/**
	 * Mark this ResultColumn as a grouping column in the SELECT list
	 */
	void markAsGroupingColumn() {
		_isGroupingColumn = true;
	}

	/**
	 * Look for and reject ?/-?/+? parameter under this ResultColumn. This is
	 * called for SELECT statements.
	 *
	 * @exception StandardException
	 *                Thrown if a ?/-?/+? parameter was found directly under
	 *                this ResultColumn.
	 */

	void rejectParameter() throws StandardException {
		if ((_expression != null) && (_expression.isParameterNode()))
			throw StandardException
					.newException(SQLState.LANG_PARAM_IN_SELECT_LIST);
	}

	/*
	 * * The following methods implement the Comparable interface.
	 */
	public int compareTo(ResultColumn other) {
		ResultColumn otherResultColumn = other;

		return this.getColumnPosition() - otherResultColumn.getColumnPosition();
	}

	/**
	 * Mark this column as being updated by an update statement.
	 */
	void markUpdated() {
		_updated = true;
	}

	/**
	 * Mark this column as being updatable, so we can make sure it is in the
	 * "for update" list of a positioned update.
	 */
	void markUpdatableByCursor() {
		_updatableByCursor = true;
	}

	/**
	 * Tell whether this column is being updated.
	 *
	 * @return true means this column is being updated.
	 */
	boolean updated() {
		return _updated;
	}

	/**
	 * Tell whether this column is updatable by a positioned update.
	 *
	 * @return true means this column is updatable
	 */
	@Override
	public boolean updatableByCursor() {
		return _updatableByCursor;
	}

	/**
	 * Make a copy of this ResultColumn in a new ResultColumn
	 *
	 * @return A new ResultColumn with the same contents as this one
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */
	ResultColumn cloneMe() throws StandardException {
		ResultColumn newResultColumn;
		ValueNode cloneExpr;

		/*
		 * If expression is a ColumnReference, then we want to have the RC's
		 * clone have a clone of the ColumnReference for it's expression. This
		 * is for the special case of cloning the SELECT list for the HAVING
		 * clause in the parser. The SELECT generated for the HAVING needs its
		 * own copy of the ColumnReferences.
		 */
		if (_expression instanceof ColumnReference) {
			cloneExpr = ((ColumnReference) _expression).getClone();
		} else {
			cloneExpr = _expression;
		}

		/* If a columnDescriptor exists, then we must propagate it */
		if (_columnDescriptor != null) {
			newResultColumn = new ResultColumn(_columnDescriptor, _expression,
					getContextManager());
			newResultColumn.setExpression(cloneExpr);
		} else {
			newResultColumn = new ResultColumn(getName(), cloneExpr,
					getContextManager());
		}

		/* Set the VirtualColumnId and name in the new node */
		newResultColumn.setVirtualColumnId(getVirtualColumnId());

		/* Set the type and name information in the new node */
		newResultColumn.setName(getName());
		newResultColumn.setType(getTypeServices());
		newResultColumn.setNameGenerated(isNameGenerated());

		// For OFFSET/FETCH we need the also clone table name to avoid failing
		// check #2 in EmbedResultSet#checksBeforeUpdateXXX. Clone schema for
		// good measure...
		newResultColumn.setSourceTableName(getSourceTableName());
		newResultColumn.setSourceSchemaName(getSourceSchemaName());

		/*
		 * Set the "is generated for unmatched column in insert" status in the
		 * new node This if for bug 4194
		 */
		if (isGeneratedForUnmatchedColumnInInsert())
			newResultColumn.markGeneratedForUnmatchedColumnInInsert();

		/* Set the "is referenced" status in the new node */
		if (isReferenced())
			newResultColumn.setReferenced();

		/* Set the "updated" status in the new node */
		if (updated())
			newResultColumn.markUpdated();

		/* Setthe "updatable by cursor" status in the new node */
		if (updatableByCursor())
			newResultColumn.markUpdatableByCursor();

		if (isAutoincrementGenerated())
			newResultColumn.setAutoincrementGenerated();

		if (isAutoincrement())
			newResultColumn.setAutoincrement();
		if (isGroupingColumn())
			newResultColumn.markAsGroupingColumn();

		if (isRightOuterJoinUsingClause()) {
			newResultColumn.setRightOuterJoinUsingClause(true);
		}

		if (getJoinResultSet() != null) {
			newResultColumn.setJoinResultset(getJoinResultSet());
		}

		if (isGenerated()) {
			newResultColumn.markGenerated();
		}

		newResultColumn.copyTagsFrom(this);

		return newResultColumn;
	}

	/**
	 * Get the maximum size of the column
	 *
	 * @return the max size
	 */
	int getMaximumColumnSize() {
		return getTypeServices().getTypeId().getApproximateLengthInBytes(
				getTypeServices());
	}

	@Override
	public DataTypeDescriptor getTypeServices() {
		DataTypeDescriptor type = super.getTypeServices();
		if (type != null)
			return type;

		if (getExpression() != null)
			return getExpression().getTypeServices();

		return null;
	}

	/**
	 * Return the variant type for the underlying expression. The variant type
	 * can be: VARIANT - variant within a scan (method calls and non-static
	 * field access) SCAN_INVARIANT - invariant within a scan (column references
	 * from outer tables) QUERY_INVARIANT - invariant within the life of a query
	 * CONSTANT - constant
	 *
	 * @return The variant type for the underlying expression.
	 * @exception StandardException
	 *                thrown on error
	 */
	@Override
	protected int getOrderableVariantType() throws StandardException { 
		return 9;
	}

	/**
	 * Accept the visitor for all visitable children of this node.
	 * 
	 * @param v
	 *            the visitor
	 *
	 * @exception StandardException
	 *                on error
	 */
	@Override
	void acceptChildren(Visitor v) throws StandardException {
		super.acceptChildren(v);

		if (_expression != null) {
			setExpression((ValueNode) _expression.accept(v));
		}
	}

	/**
	 * Verify that this RC is orderable.
	 *
	 * @exception StandardException
	 *                Thrown on error
	 */
	void verifyOrderable() throws StandardException {
		 
	}

	/**
	 * If this ResultColumn is bound to a column in a table get the column
	 * descriptor for the column in the table. Otherwise return null.
	 */
	ColumnDescriptor getTableColumnDescriptor() {
		return _columnDescriptor;
	}

	/**
	 * Returns true if this result column is a placeholder for a generated
	 * autoincrement value.
	 */
	boolean isAutoincrementGenerated() {
		return _autoincrementGenerated;
	}

	void setAutoincrementGenerated() {
		_autoincrementGenerated = true;
	}

	void resetAutoincrementGenerated() {
		_autoincrementGenerated = false;
	}

	public boolean isAutoincrement() {
		return _autoincrement;
	}

	void setAutoincrement() {
		_autoincrement = true;
	}

	public boolean isGroupingColumn() {
		return _isGroupingColumn;
	}

	/**
	 * @exception StandardException
	 *                Thrown on error
	 */
	@SuppressWarnings("fallthrough")
	private DataValueDescriptor convertConstant(TypeId toTypeId, int maxWidth,
			DataValueDescriptor constantValue) throws StandardException {
		int formatId = toTypeId.getTypeFormatId();
		DataValueFactory dvf = getDataValueFactory();
		switch (formatId) {
		default:
		case StoredFormatIds.CHAR_TYPE_ID:
			return constantValue;

		case StoredFormatIds.VARCHAR_TYPE_ID:
			String sourceValue = constantValue.getString();
			int sourceWidth = sourceValue.length();
			int posn;

			/*
			 * * If the input is already the right length, no normalization is*
			 * necessary - just return the source.*
			 */

			if (sourceWidth <= maxWidth) {
				if (formatId == StoredFormatIds.VARCHAR_TYPE_ID)
					return dvf.getVarcharDataValue(sourceValue);
			}

			/*
			 * * Check whether any non-blank characters will be truncated.
			 */
			for (posn = maxWidth; posn < sourceWidth; posn++) {
				if (sourceValue.charAt(posn) != ' ') {
					String typeName = null;
					if (formatId == StoredFormatIds.VARCHAR_TYPE_ID)
						typeName = TypeId.VARCHAR_NAME;
					throw StandardException.newException(
							SQLState.LANG_STRING_TRUNCATION, typeName,
							StringUtil.formatForPrint(sourceValue),
							String.valueOf(maxWidth));
				}
			}

			if (formatId == StoredFormatIds.VARCHAR_TYPE_ID)
				return dvf.getVarcharDataValue(sourceValue.substring(0,
						maxWidth));

		case StoredFormatIds.LONGVARCHAR_TYPE_ID:
			// No need to check widths here (unlike varchar), since no max width
			return dvf.getLongvarcharDataValue(constantValue.getString());

		}
	}

	public TableName getTableNameObject() {
		return null;
	}

	/* Get the wrapped reference if any */
	public ColumnReference getReference() {
		return _reference;
	}

	/** Get the column descriptor */
	ColumnDescriptor getColumnDescriptor() {
		return _columnDescriptor;
	}

	/**
	 * Get the source BaseColumnNode for this result column. The BaseColumnNode
	 * cannot be found unless the ResultColumn is bound and is a simple
	 * reference to a column in a BaseFromTable.
	 *
	 * @return a BaseColumnNode, or null if a BaseColumnNode cannot be found
	 */
	BaseColumnNode getBaseColumnNode() {
		ValueNode vn = _expression;
		while (true) {
			if (vn instanceof ResultColumn) {
				vn = ((ResultColumn) vn)._expression;
			} else if (vn instanceof ColumnReference) {
				vn = ((ColumnReference) vn).getSource();
			} else if (vn instanceof VirtualColumnNode) {
				vn = ((VirtualColumnNode) vn).getSourceColumn();
			} else if (vn instanceof BaseColumnNode) {
				return (BaseColumnNode) vn;
			} else {
				return null;
			}
		}
	}

	/**
	 * Search the tree beneath this ResultColumn until we find the number of the
	 * table to which this RC points, and return that table number. If we can't
	 * determine which table this RC is for, then return -1.
	 *
	 * There are two places we can find the table number: 1) if our expression
	 * is a ColumnReference, then we can get the target table number from the
	 * ColumnReference and that's it; 2) if expression is a VirtualColumnNode,
	 * then if the VirtualColumnNode points to a FromBaseTable, we can get that
	 * FBT's table number; otherwise, we walk the VirtualColumnNode-ResultColumn
	 * chain and do a recursive search.
	 *
	 * @return The number of the table to which this ResultColumn points, or -1
	 *         if we can't determine that from where we are.
	 */
	int getTableNumber() throws StandardException {
		if (_expression instanceof ColumnReference)
			return ((ColumnReference) _expression).getTableNumber();
		else if (_expression instanceof VirtualColumnNode) {
			VirtualColumnNode vcn = (VirtualColumnNode) _expression;

			// If the VCN points to a FromBaseTable, just get that
			// table's number.
			if (vcn.getSourceResultSet() instanceof FromBaseTable) {
				return ((FromBaseTable) vcn.getSourceResultSet())
						.getTableNumber();
			}

			// Else recurse down the VCN.
			return vcn.getSourceColumn().getTableNumber();
		}

		// We can get here if expression has neither a column
		// reference nor a FromBaseTable beneath it--for example,
		// if it is of type BaseColumnNode.
		return -1;
	}

	boolean isEquivalent(ValueNode o) throws StandardException {
		if (isSameNodeKind(o)) {
			ResultColumn other = (ResultColumn) o;
			if (_expression != null) {
				return _expression.isEquivalent(other._expression);
			}
		}

		return false;
	}

	/**
	 * Return true if this result column represents a generated column.
	 */
	public boolean hasGenerationClause() {
		if ((_columnDescriptor != null)
				&& _columnDescriptor.hasGenerationClause()) {
			return true;
		} else {
			return false;
		}
	}

}
